import { _decorator, Component, Node, EventTouch, Vec3, UITransform, find, input, Input, EventKeyboard, KeyCode } from 'cc';
const { ccclass, property } = _decorator;
import { Player } from './Player';
import { GameManager } from './GameManager';

@ccclass('Joystick')
export class Joystick extends Component {
    @property({type: Node})
    playerNode: Node = null!

    joystickBtn = new Node()
    dirVec3 = new Vec3(0, 1, 0)
    originalPos: Vec3 = new Vec3()
    isTouchingInRightArea: boolean = false
    _isUsingKeyboard: boolean = false

    playerComp: Player = null
    gameManager: GameManager = null
    nodeUITransform = new UITransform()
    canvasUITransform = new UITransform()

    start() {
        this.initJoystick()
        this.initComponents()
        this.initTouchEvents()
    }

    /** 
     * @zh
     * 初始化摇杆按钮节点。
    */
    initJoystick() {
        this.node.setSiblingIndex(5000)
        this.joystickBtn = this.node.children[0]
        this.originalPos = new Vec3(this.node.position)
    }

    /** 
     * @zh
     * 初始化组件。
    */
    initComponents() {
        this.playerComp = this.playerNode.getComponent(Player)
        this.nodeUITransform = this.node.getComponent(UITransform)
        this.gameManager = find('Canvas').getComponent(GameManager)
        this.canvasUITransform = find('Canvas').getComponent(UITransform)
    }

    /** 
     * @zh
     * 初始化触摸监听事件。
    */
    initTouchEvents() {
        this.node.parent.on(Node.EventType.TOUCH_START, this.onTouchStart, this)
        this.node.parent.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this)
        this.node.parent.on(Node.EventType.TOUCH_END, this.onTouchEnd, this)
        this.node.parent.on(Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this)

        input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this)
        input.on(Input.EventType.KEY_UP, this.onKeyUp, this)
    }

    onKeyDown(event: EventKeyboard) {
        if (this.playerComp.isDead || this.gameManager.isGamePaused) {
            return
        }

        this._isUsingKeyboard = true
        switch(event.keyCode) {
            case KeyCode.KEY_W:
                this.playerComp.yDir = 1
                break
            case KeyCode.KEY_S:
                this.playerComp.yDir = -1
                break
            case KeyCode.KEY_A:
                this.playerComp.xDir = -1
                this.playerNode.setScale(new Vec3(-1, 1, 0))
                this.playerNode.getChildByName('State').setScale(new Vec3(-1, 1, 0))
                break
            case KeyCode.KEY_D:
                this.playerComp.xDir = 1
                this.playerNode.setScale(new Vec3(1, 1, 0))
                this.playerNode.getChildByName('State').setScale(new Vec3(1, 1, 0))
                break
        }
        
        // 当同时按下W和A，或者W和D时，会有一个斜向移动
        if (this.playerComp.xDir !== 0 || this.playerComp.yDir !== 0) {
            this.playerComp.isMoving = true
        }
    }

    onKeyUp(event: EventKeyboard) {
        switch(event.keyCode) {
            case KeyCode.KEY_W:
            case KeyCode.KEY_S:
                this.playerComp.yDir = 0
                break
            case KeyCode.KEY_A:
            case KeyCode.KEY_D:
                this.playerComp.xDir = 0
                break
        }

        if (this.playerComp.xDir === 0 && this.playerComp.yDir === 0) {
            this.playerComp.isMoving = false
            this._isUsingKeyboard = false
        }
    }

    onTouchStart(event: EventTouch) {
        if (this.playerComp.isDead || this.gameManager.isGamePaused) {
            return
        }

        this._isUsingKeyboard = false // If touch starts, stop keyboard control
        // 获取触摸坐标
        let loc = event.getUILocation()
        let pos = this.canvasUITransform.convertToNodeSpaceAR(new Vec3(loc.x, loc.y, 0))

        // 把屏幕分成四块，只有点击在左下方位置才可以操作摇杆
        if (pos.x > 0 || pos.y > 0) {
            this.isTouchingInRightArea = false
            return
        }
        else {
            this.isTouchingInRightArea = true
        }

        // 先设置摇杆面板位置
        this.node.setPosition(pos)

        // 再设置摇杆按钮位置
        pos = this.nodeUITransform.convertToNodeSpaceAR(new Vec3(loc.x, loc.y, 0))
        this.joystickBtn.setPosition(pos)

        // 确定方向
        this.dirVec3 = new Vec3(this.joystickBtn.position.x, this.joystickBtn.position.y, 0).normalize()
        if (this.dirVec3.x > 0) {
            this.playerComp.xDir = 1
            this.playerNode.setScale(new Vec3(1, 1, 0))
        }
        else if (this.dirVec3.x < 0) {
            this.playerComp.xDir = -1
            this.playerNode.setScale(new Vec3(-1, 1, 0))
        }

        if (this.dirVec3.y > 0) {
            this.playerComp.yDir = 1
        }
        else if (this.dirVec3.y < 0) {
            this.playerComp.yDir = -1
        }

        this.playerComp.isMoving = true
    }

    onTouchMove(event: EventTouch) {
        if (!this.isTouchingInRightArea) {
            return
        }
        
        // 设置摇杆按钮位置
        let posDelta = event.getDelta()
        this.joystickBtn.setPosition(new Vec3(this.joystickBtn.position).add3f(posDelta.x, posDelta.y, 0))
        
        this.dirVec3 = new Vec3(this.joystickBtn.position.x, this.joystickBtn.position.y, 0).normalize()
        if (this.dirVec3.x > 0) {
            this.playerComp.xDir = 1
            this.playerNode.setScale(new Vec3(1, 1, 0))
            this.playerNode.getChildByName('State').setScale(new Vec3(1, 1, 0)) // State状态文本节点方向不受父节点影响
        }
        else if (this.dirVec3.x < 0) {
            this.playerComp.xDir = -1
            this.playerNode.setScale(new Vec3(-1, 1, 0))
            this.playerNode.getChildByName('State').setScale(new Vec3(-1, 1, 0)) // State状态文本节点方向不受父节点影响
        }

        if (this.dirVec3.y > 0) {
            this.playerComp.yDir = 1
        }
        else if (this.dirVec3.y < 0) {
            this.playerComp.yDir = -1
        }

        this.playerComp.isMoving = true
    }

    onTouchEnd(event: EventTouch) {
        this.node.setPosition(this.originalPos)
        this.joystickBtn.setPosition(Vec3.ZERO)
        this.isTouchingInRightArea = false
        this.playerComp.isMoving = false
    }

    onTouchCancel(event: EventTouch) {
        this.node.setPosition(this.originalPos)
        this.joystickBtn.setPosition(Vec3.ZERO)
        this.isTouchingInRightArea = false
        this.playerComp.isMoving = false
    }

    /** 
     * @zh
     * 限制摇杆按钮位置，防止移动到摇杆面板外。
    */
    limitJoystickBtn() {
        let x = this.joystickBtn.position.x
        let y = this.joystickBtn.position.y

        let len = new Vec3(x, y, 0).length()
        let maxLen = this.nodeUITransform.width / 2

        let ratio = len / maxLen
        if (ratio > 1) {
            this.joystickBtn.setPosition(x/ratio, y/ratio, 0)
        }
    }

    update (deltaTime: number) {
        // 限制摇杆按钮位置
        if (!this._isUsingKeyboard) { // Only limit joystick button if not using keyboard
            this.limitJoystickBtn()
        }
                
        // 移动玩家
        if (this.playerComp.isMoving && !this.playerComp.isDead) {
            this.playerComp.move()
        }
    }
}

